package com.ham.mud;

import com.ham.mud.characters.Vitals;
import com.ham.mud.characters.player.Player;
import com.ham.mud.rooms.Room;
import com.ham.mud.rooms.RoomService;
import com.ham.mud.state.ConnectionState;
import com.ham.mud.state.LoginState;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.net.SocketException;

/**
 * Created by hlucas on Jun 16, 2011 at 12:19:41 PM
 */
public class ServerConnection implements Runnable {
    boolean isConnected = false;

    Player player;
    DataInputStream in;
    PrintStream out;
    Socket socket;

    ConnectionState state;

    public ServerConnection(Socket newSocket) {
        this.socket = newSocket;
    }

    public void run() {
        String remoteAddress = socket.getRemoteSocketAddress().toString();
        System.out.println("Connected: " + remoteAddress);

        try {
            isConnected = socket.isConnected();
            in = new DataInputStream(socket.getInputStream());
            out = new PrintStream(socket.getOutputStream());
            state = new LoginState(this);
            while(isConnected && socket.isConnected() && !socket.isInputShutdown() && !socket.isOutputShutdown()) {
                process();
            }
            isConnected = false;
        } catch(Exception e) {
            e.printStackTrace();
        } finally {
            close();
        }

        Room room = RoomService.getRoom(player.getZone(), player.getAtX(), player.getAtY());
        room.removePlayer(this, "void");

        Runner.STATIC_INSTANCE.removeConnection(this);
        System.out.println("Disconnected: " + remoteAddress);
    }

    private void process() throws IOException {
        try {
            String line;
            while((line = in.readLine()) != null) {
                processLine(line);
            }
        } catch(SocketException e) {
            isConnected = false;
        }
    }

    private void processLine(String line) throws IOException {
        state.processInput(line);
    }

    public void preTick() {
        state.preTick();
    }

    public void tick() {
        state.tick();
    }

    public void postTick() {
        state.postTick();
    }

    public ConnectionState getState() {
        return state;
    }

    public void println() {
        print(Colors.NEW_LINE);
    }

    public void println(String s) {
        print(s + Colors.NEW_LINE);
    }

    public void printSolo(String s) {
        println(Colors.NEW_LINE + s + Colors.NEW_LINE);
        showPrompt();
    }

    public void printStart(String s) {
        println(Colors.NEW_LINE + s);
    }

    public void printEnd() {
        println();
        showPrompt();
    }
    
    public void print(String s) {
        //todo: capitalize the first non whitespace character
        if(player == null) {
            out.print(Colors.format(s, false));
            return;
        }

        out.print(Colors.format(s, player.isColorEnabled()));
    }

    public void showPrompt() {
        Vitals vitals = player.getVitals();
        int tnl = player.getToNextLevel();
        String promptString = "{R%h{x/{r%H{xhp {B%v{x/{b%V{xmv {G%m{x/{g%M{xm {C%x{xtnl";
        promptString = promptString.replaceAll("%h", String.valueOf(vitals.getHealth()));
        promptString = promptString.replaceAll("%H", String.valueOf(vitals.getMaxHealth()));
        promptString = promptString.replaceAll("%v", String.valueOf(vitals.getMove()));
        promptString = promptString.replaceAll("%V", String.valueOf(vitals.getMaxMove()));
        promptString = promptString.replaceAll("%m", String.valueOf(vitals.getMana()));
        promptString = promptString.replaceAll("%M", String.valueOf(vitals.getMaxMana()));
        promptString = promptString.replaceAll("%x", String.valueOf(tnl));
        out.print(Colors.format("<" + promptString + "> ", player.isColorEnabled()));
    }

    public void changeState(ConnectionState state) {
        this.state = state;
    }

    public Player getPlayer() {
        return player;
    }

    public void setPlayer(Player player) {
        this.player = player;
    }

    public void close() {
        try {
            socket.close();
            isConnected = false;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean equals(Object obj) {
        if(!(obj instanceof ServerConnection)) return false;
        
        ServerConnection other = (ServerConnection) obj;
        String me = this.player.getName();
        String you = other.player.getName();
        return me.equals(you);
    }
}
